#!/usr/bin/env python3
#
# mk-reg.py
# Registration Macros Generator
#
# Copyright 2022 by Moshe Kaplan
# Based on make-reg.pl by Luis E. Garcia Onatnon <luis.ontanon@gmail.com>
#

import argparse
import re

files=["./lua_bitop.c",
       "./pilua_address.c",
       "./pilua_byte_array.c",
       "./pilua_capture_info.c",
       "./pilua_column.c",
       "./pilua_dir.c",
       "./pilua_dissector.c",
       "./pilua_dumper.c",
       "./pilua_field.c",
       "./pilua_file.c",
       "./pilua_file_common.c",
       "./pilua_file_handler.c",
       "./pilua_frame_info.c",
       "./pilua_gui.c",
       "./pilua_int64.c",
       "./pilua_internals.c",
       "./pilua_listener.c",
       "./pilua_nstime.c",
       "./pilua_pinfo.c",
       "./pilua_pref.c",
       "./pilua_proto.c",
       "./pilua_proto_expert.c",
       "./pilua_proto_field.c",
       "./pilua_struct.c",
       "./pilua_tree.c",
       "./pilua_tvb.c",
       "./pilua_utility.c",
       "./pilua_wtap.c",
       ]

def parse_file(file_content):
    # extract classes, functions, and internal functions
    # and return them as a tuple
    CLASS_PATTERN = r'PILUA_CLASS_DEFINE(?:_BASE)?\050\s*([A-Za-z0-9]+)'
    FUNCTION_PATTERN = r'PILUA_FUNCTION\s+pilua_([a-z_0-9]+)'
    INTERN_FUNCTION_PATTERN = r'PILUA_INTERN_FUNCTION\s+pilua_([a-z_0-9]+)'

    class_matches = re.findall(CLASS_PATTERN, file_content)
    function_matches = re.findall(FUNCTION_PATTERN, file_content)
    intern_function_matches = re.findall(INTERN_FUNCTION_PATTERN, file_content)
    return class_matches, function_matches, intern_function_matches


def generate_declare_pilua_h(classes, functions, intern_functions):
    output_lines = []
    output_lines += ["/* This file is automatically generated by mk-reg.py; do not edit! */\n"]
    # output_lines += ["#define PILUA_DECLARE_CLASSES() \\"]
    for lua_class in classes:
        output_lines += ["PILUA_CLASS_DECLARE({lua_class});".format(lua_class=lua_class)]

    output_lines += ["\n"]
    # output_lines += ["#define PILUA_DECLARE_FUNCTIONS() \\"]
    for lua_function in functions:
        output_lines += ["PILUA_FUNCTION pilua_{lua_function}(lua_State* L);".format(lua_function=lua_function)]

    for lua_intern_function in intern_functions:
        output_lines += ["PILUA_INTERN_FUNCTION pilua_{lua_intern_function}(lua_State* L);".format(lua_intern_function=lua_intern_function)]

    output_lines += ["\n"]
    output_lines += ["extern void pilua_register_classes(lua_State* L);"]
    output_lines += ["extern void pilua_register_functions(lua_State* L);"]
    output_lines += ["\n"]

    return "\n".join(output_lines)


def generate_register_pilua_c(classes, functions, intern_functions):
    output_lines = []
    output_lines += ["/* This file is automatically generated by mk-reg.py; do not edit! */\n"]
    # output_lines += ['#include "config.h"']
    output_lines += ['#include "pilua.h"\n']
    # output_lines += ['#include "lua_bitop.h"\n']
    output_lines += ["inline void pilua_register_module(lua_State* L, const char *name, lua_CFunction func)"]
    output_lines += ["{"]
    output_lines += ["    lua_pushcfunction(L, func);"]
    output_lines += ["    lua_call(L, 0, 0);"]
    output_lines += ["}\n"]
    output_lines += ["inline void pilua_register_function(lua_State* L, const char *name, lua_CFunction func)"]
    output_lines += ["{"]
    output_lines += ["    lua_pushcfunction(L, func);"]
    output_lines += ["    lua_setglobal(L, name);"]
    output_lines += ["}\n"]
    output_lines += ["void pilua_register_classes(lua_State* L)"]
    output_lines += ["{"]
    for lua_class in classes:
        output_lines += ["    pilua_register_module(L, \"{lua_class}\", {lua_class}_register);".format(lua_class=lua_class)]

    # output_lines += ["    pilua_register_module(L, \"bit\", luaopen_bit);"]

#    output_lines += ["\n    lua_pushcfunction(L, luaopen_rex_pcre2);"]
#    output_lines += ["    lua_call(L, 0, 1);"]
#    output_lines += ["    lua_setglobal(L, \"rex_pcre2\");\n"]

    output_lines += ["}\n"]

    output_lines += ["void pilua_register_functions(lua_State* L)"]
    output_lines += ["{"]
    for lua_function in functions:
        output_lines += ["    pilua_register_function(L, \"{lua_function}\", pilua_{lua_function});".format(lua_function=lua_function)]

    for lua_intern_function in intern_functions:
        output_lines += ["    pilua_register_function(L, \"{lua_intern_function}\", pilua_{lua_intern_function});".format(lua_intern_function=lua_intern_function)]

    output_lines += ["}\n"]

    return "\n".join(output_lines)


def main():

    lua_classes = []
    lua_functions = []
    lua_intern_functions = []
    for filename in files:
        with open(filename, encoding='utf-8') as fs:
            class_matches, function_matches, intern_function_matches = parse_file(fs.read())
        lua_classes += class_matches
        lua_functions += function_matches
        lua_intern_functions += intern_function_matches

    declare_pilua_h_content = generate_declare_pilua_h(lua_classes, lua_functions, lua_intern_functions)
    register_pilua_c_content = generate_register_pilua_c(lua_classes, lua_functions, lua_intern_functions)

    with open('register_pilua.c', mode='w', encoding='utf-8') as fc:
        fc.write(register_pilua_c_content)

    with open('declare_pilua.h', mode='w', encoding='utf-8') as fh:
        fh.write(declare_pilua_h_content)


if __name__ == '__main__':
    main()
